//学习进程的替换：
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>

//默认环境变量需要声明：
extern char **environ;

int main()
{
  pid_t id =fork();
  if(id==0)
  {
    
    printf("before:i am a process,pid:%d\n",getpid());
    sleep(5);
    //进程替换的标准写法：
    //execl("/usr/bin/ls","ls","-a","-l",NULL);//这里的参数列表是可变的
  
    //可以使用这个替换指令调用其他语言的程序，无论是什么语言，例如shell，py，java
    //execl("./other.exe","other.exe",NULL);
    
    //也可以使用execv传命令行参数给调用的程序的main函数：
    char*const myargv[]={"other.exe","-a","-b",NULL};//可以在替换程序的时候把命令行参数传递过去
   // execv("./other.exe",myargv);
   
    char *const myenv[]={"MYVAL=1111","HXKPATH=/usr/bin/xxx",NULL};

    //也可以使用带e的替换函数传递环境变量给调用的程序：
   // execle("./other.exe","other.exe","-a","-b",NULL,myenv);

    putenv("HXK=133");//增加的环境变量自己可以使用自己的所有子进程也会默认继承下去，所以环境变量会越往子进程下面走越多，是一个增多的趋势
    execle("./other.exe","other.exe","-a","-b",NULL,environ);//environ是默认的环境变量，每个进程被创建的时候都会默认继承父进程的环境变量，除非我们自己去覆盖它


    //注意：进程替换并没有创建新进程，只是进行进程的代码和数据的替换工作 

    //进程替换后不会执行这条语句之后的代码了，而是执行替换的目标进程，目标进程执行结束后进程就直接退出
    //这说明了进程除了内存会写时拷贝，代码区也会写时拷贝，需要执行其程序的代码的时候就直接执行其他程序的代码
    

    //进程替换的一个作用：由于进程替换成功后，是不会执行原本子进程后续的代码的，如果执行了后续代码，说明进程替换出错了
    printf("after\n");
    exit(1);//可以通过退出码来表示是否进程替换出错了，如果出错了就会执行这里原本设置的退出码
  }
  pid_t ret =waitpid(id,NULL,0);
  if(ret>0)
  {
    printf("wait success\n");
  }
  sleep(5);


  return 0;
}
//补充：exec*的函数只有失败返回值，没有成功返回值

//进程替换接口的介绍：所有的接口第一个参数都是要替换的程序的绝对或者相对路径，这些接口函数后面的部分才又不同
//1，execl,后面的参数就像是list一样，一个个传执行选项
//例如：execl("/usr/bin/ls","ls","-a","-l",NULL);//第一个参数是路径，第二个参数ls是为了说明要执行什么程序，后面的也一样
//2，execlp，第一个参数不用写路径了，直接告诉程序文件的名字，会自动在默认的PATH环境变量中查找，注意：带p的就是地址的意思，也就是不用自己传地址了
//例如：execlp("ls","ls","-a","-l",NULL);//自动去查找ls程序文件
//3，execv（const char* path,char *const argv[]）,第一个参数还是路径，但是v就像vector一样，这里不在使用可变参数列表，而是直接将所有的命令字符串和命令的选项以字符指针的方式放在数组指针数组里面一起传
//例如：要先写一个命令字符串数组：char*const myargv[]={"ls","-l","-a",NULL};//数组也要以NULL结尾
//然后再调用：execv("/usr/bin/ls",myargv);//效果和上面一样，就是把命令和选项一次性放在数组里面传参而已
//4，execvp，就是p,v的结合体，不用告诉路径并且是传一个包含要执行的目标程序，选项的字符数组
//例如：execvp("ls",myargv);//只用写要查找的文件名和数组即可
//5,带e替换函数就可以传递环境变量给目标程序:
//例如：execle("./other.exe","other.exe","-a","-b",NULL,myenv);
//注意：传递环境变量时，1，以追加的方式添加环境变量使用putenv的方式，并且传递默认环境变量environ(注意：使用默认环境变量需要声明：extern char **environ;)，2，如果要覆盖的方式传环境变量就要自己写一个环境变量数组传入
